package net.realsee.service.system.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import lombok.RequiredArgsConstructor;
import net.realsee.common.exception.ServiceException;
import net.realsee.common.utils.file.FileUtils;
import net.realsee.domain.system.bo.SysLogFileBo;
import net.realsee.domain.system.vo.SysLogFileVo;
import net.realsee.framework.config.properties.LogFileProperties;
import net.realsee.framework.core.domain.PageQuery;
import net.realsee.framework.core.page.TableDataInfo;
import net.realsee.service.system.ISysLogFileService;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 日志文件 服务层实现
 *
 * @author 孙正华
 * @since 2023/7/21 11:01
 */
@RequiredArgsConstructor
@Service
public class SysLogFileServiceImpl implements ISysLogFileService {

    /**
     * 系统基础配置
     */
    private final LogFileProperties logFileProperties;

    /**
     * 获取日志文件列表
     */
    @Override
    public TableDataInfo<SysLogFileVo> list(SysLogFileBo bo, PageQuery pageQuery) {
        List<SysLogFileVo> logFileList = new ArrayList<>();
        long totalSize = 0;

        File logFilePath = new File(logFileProperties.getPath());
        if (!FileUtils.exist(logFilePath) || !FileUtils.isDirectory(logFilePath)) {
            throw new ServiceException("查询不到日志目录");
        }

        String name = bo.getName();
        String beginTime = bo.getBeginTime();
        String endTime = bo.getEndTime();
        File[] fileList = logFilePath.listFiles();
        if (ArrayUtil.isNotEmpty(fileList)) {
            for (File file : fileList) {
                if (StrUtil.isNotBlank(name) && !file.getName().contains(name)) {
                    continue;
                }
                String lastModifiedTimeStr = DateUtil.formatDateTime(new Date(file.lastModified()));
                if (StrUtil.isNotBlank(beginTime) && DateUtil.compare(DateUtil.parseDate(beginTime), DateUtil.parseDate(lastModifiedTimeStr)) > 0) {
                    continue;
                }
                if (StrUtil.isNotBlank(endTime) && DateUtil.compare(DateUtil.parseDate(endTime), DateUtil.parseDate(lastModifiedTimeStr)) < 0) {
                    continue;
                }
                SysLogFileVo fileVo = new SysLogFileVo();
                fileVo.setName(file.getName());
                fileVo.setPath(file.getAbsolutePath());
                fileVo.setSize(getFileSizeAsString(file));
                fileVo.setLastModifiedTime(new Date(file.lastModified()));
                logFileList.add(fileVo);
            }
            // 总行数
            totalSize = logFileList.size();

            // 分页
            logFileList = logFileList.stream()
                .sorted(Comparator.comparing(SysLogFileVo::getLastModifiedTime).reversed().thenComparing(SysLogFileVo::getName))
                .skip((long) (pageQuery.getPageNum() - 1) * pageQuery.getPageSize()) // 跳过前面的元素，计算起始索引
                .limit(pageQuery.getPageSize()) // 限制返回的元素数量
                .collect(Collectors.toList()); // 将分页后的结果收集成一个新的List
        }

        TableDataInfo<SysLogFileVo> rspData = new TableDataInfo<>();
        rspData.setMsg("查询成功");
        rspData.setCode(HttpStatus.HTTP_OK);
        rspData.setRows(logFileList);
        rspData.setTotal(totalSize);
        return rspData;
    }

    /**
     * 查询日志文件尾行内容
     */
    @Override
    public Map<String, String> tail(SysLogFileBo param) {
        Map<String, String> result = new HashMap<>();
        File logFilePath = new File(param.getPath());
        if (!FileUtils.exist(logFilePath) || FileUtils.isDirectory(logFilePath)) {
            throw new ServiceException("查询不到日志文件");
        }
        Integer lineNum = param.getLineNum();
        if (ObjectUtil.isNull(lineNum) || lineNum == 0) {
            lineNum = logFileProperties.getReadLineNum();
        }
        List<String> lines = FileUtils.readLastLines(logFilePath, lineNum);
        result.put(param.getName(), String.join("\n", lines));
        return result;
    }

    /**
     * 下载日志文件
     */
    @Override
    public void download(SysLogFileBo param, HttpServletResponse response) throws IOException {
        File logFilePath = new File(param.getPath());
        if (!FileUtils.exist(logFilePath) || FileUtils.isDirectory(logFilePath)) {
            throw new ServiceException("查询不到日志文件");
        }
        FileUtils.setAttachmentResponseHeader(response, param.getName());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        try (InputStream inputStream = new FileInputStream(logFilePath)) {
            int available = inputStream.available();
            IoUtil.copy(inputStream, response.getOutputStream(), available);
            response.setContentLength(available);
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 删除日志文件
     */
    @Override
    public boolean delete(String filePath) {
        File logFilePath = new File(filePath);
        if (!FileUtils.exist(logFilePath) || FileUtils.isDirectory(logFilePath)) {
            throw new ServiceException("查询不到日志文件");
        }
        return FileUtils.del(logFilePath);
    }

    private String getFileSizeAsString(File file) {
        // 获取文件大小（字节）
        long fileSizeInBytes = file.length();

        // 自动转换为KB或MB
        String fileSizeAsString;
        if (fileSizeInBytes < 1024) {
            fileSizeAsString = fileSizeInBytes + " 字节";
        } else if (fileSizeInBytes < 1024 * 1024) {
            double fileSizeInKB = (double) fileSizeInBytes / 1024;
            fileSizeAsString = String.format("%.2f KB", fileSizeInKB);
        } else {
            double fileSizeInMB = (double) fileSizeInBytes / (1024 * 1024);
            fileSizeAsString = String.format("%.2f MB", fileSizeInMB);
        }
        return fileSizeAsString;
    }
}
